package com.loren.oauth.utils;

import com.loren.oauth.exception.SystemException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;

import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
public class BeanConvertUtils {

    /**
     * Object -> T
     */
    public static <T> T sourceToTarget(Object source, Class<T> target) {
        try {
            T instance = target.newInstance();
            if (source != null) {
                BeanUtils.copyProperties(instance, source);
            }
            return instance;
        } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
            log.error("bean convert error occurred", e);
            throw new SystemException("an error has occured on bean convert");
        }
    }

    /**
     * Map<String, Object> -> T
     */
    public static <T> T sourceMapToTarget(Map<String, Object> sourceMap, Class<T> target) {
        try {
            T instance = target.newInstance();
            BeanUtils.populate(instance, sourceMap);
            return instance;
        } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
            log.error("bean convert error occurred", e);
            throw new SystemException("an error has occured on bean convert");
        }
    }

    /**
     * List<Object> -> List<T>
     */
    public static <T> List<T> sourceListToTargetList(List<?> sourceList, Class<T> target) {
        return sourceList.stream().map(o -> sourceToTarget(o, target)).collect(Collectors.toList());
    }

    /**
     * Set<Object> -> Set<T>
     */
    public static <T> Set<T> sourceSetToTargetSet(Set<?> sourceSet, Class<T> target) {
        return sourceSet.stream().map(o -> sourceToTarget(o, target)).collect(Collectors.toSet());
    }

    /**
     * List<Map<String, Object>> -> List<T>
     */
    public static <T> List<T> sourceMapListToTargetList(List<Map<String, Object>> sourceMapList, Class<T> target) {
        return sourceMapList.stream().map(sourceMap -> sourceMapToTarget(sourceMap, target)).collect(Collectors.toList());
    }

}
